home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
COMM
/
MSKRMSRC.ARJ
/
MSSSCP.ASM
< prev
next >
Wrap
Assembly Source File
|
1991-10-24
|
72KB
|
2,091 lines
NAME mssscp
; File MSSSCP.ASM
include mssdef.h
; Copyright (C) 1982,1991, Trustees of Columbia University in the
; City of New York. Permission is granted to any individual or
; institution to use, copy, or redistribute this software as long as
; it is not sold for profit and this copyright notice is retained.
; Edit History
; 6 Sept 1991 version 3.11
; Last edit 6 Sept 1991
; 4 June 1991 Make label searches be global so the next higher level is
; searched if the present level does not contain the target.
; 6 June 1989 Limit echoing of received chars by OUTPUT to 100, to quench
; verbose hosts. From Dan Norstedt.
; 4 May 1989 Make input/reinput scan buffer be allocated dynamically. Allow
; for that size to be set via Environment as Kermit initializes.
;
; MS Kermit Script routines, DEC-20 style.
; Extensively rewritten for MS Kermit 2.29a by Joe R. Doupnik 5 July 86
;;
; Created June, 1986 a.d. By James Sturdevant
; A. C. Nielsen Co. Mpls.
; 8401 Wayzata Blvd.
; Minneapolis, Mn. 55426
; (612)546-0600
;;;;;;;;
; Kermit command level usages and this file's entry points:
; Clear - clears serial port buffers. Procedure scclr.
; Echo text - displays text on local screen. Proc scecho.
; Pause [time] - waits indicated number of seconds (default is Input
; Default-timeout, 1 second typically). Proc scpau.
; IF condtion command - tests condition (SUCCESS or FAILURE just now) and
; if the condition is met executes the main-line Kermit command.
; GOTO label - rewinds Take file or Macro, locates the :label, transfers
; parsing control to the next line.
; Input [time] text - waits up to time seconds while scanning serial port
; input for a match with text. Default value for time is Input
; Default-timeout, 1 second typically). Spaces or tabs are separators
; between the time and text fields. Proc scinp.
; A carriage return typed by the local user simulates a match.
; Reinput [time] text - like INPUT but non-destructively rereads the 128 byte
; script buffer. Buffer can be added to, until full, if necessary.
; Output text - sends the text to the serial output port. Proc scout.
; Transmit text [prompt] - raw file transfer to host. Proceeds from source
; line to source line upon receipt of prompt from host or carriage
; return from us. Default prompt is linefeed. A null prompt (\0)
; causes the file to be sent with no pausing or handshaking. Note
; that linefeeds are stripped from outgoing material. Proc scxmit.
; In the above commands "text" may be replaced by "@filespec" to cause the
; one line of that file to be used instead. @CON obtains one line of
; text from the keyboard. Such "indirect command files" may be nested
; to a depth of 100. Control codes are written as decimal numbers
; in the form "\ddd" where d is a digit between 0 and 9. Carriage
; return is \13, linefeed is \10, bell is \7; the special code \255
; is used to match (Input) either cr or lf or both.
; These commands can be given individually by hand or automatically
; in a Kermit Take file; Take files may be nested.
;;;;;;;;
; These routines expect to be invoked by the Kermit command dispatcher
; and can have their default operations controlled by the Kermit Set Input
; command (implemented in file mssset.asm). They parse their own cmd lines.
; Set Input accepts arguments of
; Case Ignore or Observe (default is ignore case when matching strings)
; Default-timeout seconds (default is 5 seconds)
; Echo On or Off controls echoing of Input cmd text (default is Off)
; Timeout-action Quit or Proceed (default is Proceed)
; These conditions are passed via global variables script.incasv, .indfto,
; .inecho, .inactv, respectively, stored here in structure script.
;;;;;;;;;
public script, scout, scinp, scpau, scecho, scclr, scxmit, scwait
public goto, screinp, ifcmd, setalrm, inptim, chktmo, alrhms
public buflog, scpini, scpbuflen
linelen equ 134 ; length of working buffer line
maxtry equ 5 ; maximum number of output retries
stat_unk equ 0 ; status return codes.
stat_ok equ 1 ; have a port character
stat_cc equ 2 ; control-C typed
stat_tmo equ 4 ; timeout
stat_cr equ 8 ; carriage return typed
ifsuc equ 0 ; indicators for IF conditions
iffail equ 1
ifext equ 2
iferr equ 3
ifnot equ 4
ifctr equ 5
ifmdf equ 6
ifalarm equ 7
ifequal equ 8
ifless equ 9
ifsame equ 10
ifmore equ 11
ifllt equ 12
iflgt equ 13
data segment
extrn taklev:byte, takadr:word, portval:word, flags:byte
extrn rxtable:byte, spause:byte, errlev:byte, fsta:word
extrn kstatus:word, mcctab:byte, comand:byte, ttyact:byte
extrn keyboard:word, rdbuf:byte
; global (public) variables
script scptinfo <> ; global structure, containing:
;;inactv db 0 ; input action value (default proceed)
;;incasv db 0dfh ; input case (default ignore)
;;indfto dw 1 ; input and pause timeout (def 1 sec)
;;inecho db 1 ; echo Input cmd text (0 = no)
;;xmitfill db 0 ; non-zero to TRANSMIT filler
;;xmitlf db 0 ; non-zero to TRANSMIT LF's
;;xmitpmt db lf ; prompt between lines
; local variables
line db linelen+1 dup (0) ; line of output or input + terminator
even
scpbuflen dw 128 ; serial port local buffer def length
bufcnt dw 0 ; serial port buf byte cnt, must be 0
bufseg dw 0 ; segment of buffer
bufrdptr dw 0 ; serial port buf read ptr
bufwtptr dw 0 ; serial port buf write ptr
bufpkptr dw 0 ; peek-read pointer
bufpkcnt dw 0 ; peek-read byte count remaining
inplen dw 0 ; length of input match string
reinflg db 0 ; 0 = INPUT, else REINPUT command
notflag db 0 ; IF NOT flag
slablen dw 0 ; label length, for GOTO
status dw 0 ; general status word
fhandle dw 0 ; file handle storage place
temptr dw 0 ; temporary pointer
temptr2 dw 0 ; ditto, points to end of INPUT string
tempd dw 0 ; temp
temp dw 0 ; a temp
tempa db 0 ; another temp
wtemp db 0 ; temp for WAIT
ltype db 0 ; lex type for IF statements
retry db 0 ; number of output retries
parmsk db 7fh ; 7/8 bit parity mask
lecho db 0 ; local echo of output (0 = no)
timout dw 0 ; work area (seconds before timeout)
timhms db 4 dup (0) ; hhmmss.s time of day buffer
alrhms db 4 dup (0) ; hhmmss.s time of day alarm buffer
eolchr db LF ; end of line character
crlf db cr,lf,'$'
xfrfnf db cr,lf,'?Transmit file not found$'
xfrrer db cr,lf,'?error reading Transmit file$'
xfrcan db cr,lf,'?Transmission canceled$'
indmis db '?Indirect file not found',cr,lf,'$'
inderr db '?error reading indirect file',cr,lf,'$'
laberr db cr,lf,'?Label ":$'
laberr2 db '" was not found.',cr,lf,'$'
tmomsg db cr,lf,'?Timeout',cr,'$'
outhlp db 'line of text to be sent to remote host$'
inphlp db 'time-limit and line of text expected from remote host'
db cr,lf,' Time is number of seconds or until a specific'
db ' hh:mm:ss (24 hour clock)$'
echhlp db 'line of text to be Echoed to screen$'
ptshlp db 'amount of time to pause/wait'
db cr,lf,' Time is number of seconds or until a specific'
db ' hh:mm:ss (24 hour clock)$'
wthlp db cr,lf,'Optional modem status signals CD, CTS, DSR which must'
db ' be asserted while waiting$'
xmthlp db ' Name of file to be Transmitted$'
pmthlp db cr,lf
db ' Prompt character expected as an ACK from host (\0 for none)$'
ifdfhlp db cr,lf,' Name of macro or variable then a command$'
alrmhlp db cr,lf,' Seconds from now or time of day (HH:MM:SS) for alarm,'
db ' < 12H from present$'
ifmhlp db cr,lf,' Number, ARGC (1+argument count), COUNT, ERRORLEVEL,'
db ' KEYBOARD, VERSION$'
ifnhlp db cr,lf,' Number which errorlevel should match or exceed$'
ifnmsg db cr,lf,'?Number expected, ignoring "$'
ifnmsg2 db '"$'
discard db ' Kermit command'
db cr,lf,' "IF" condition is false, command will be ignored.$'
ifehlp1 db cr,lf,'?pair of words or variables to be compared$'
ifehlp2 db cr,lf,'?second word or variable to be compared$'
iftable db 14 ; IF command dispatch table
mkeyw 'Not',ifnot
mkeyw '<',ifless
mkeyw '=',ifsame
mkeyw '>',ifmore
mkeyw 'Alarm',ifalarm
mkeyw 'Count',ifctr
mkeyw 'Defined',ifmdf
mkeyw 'Errorlevel',iferr
mkeyw 'Equal',ifequal
mkeyw 'Exist',ifext
mkeyw 'LGT',iflgt
mkeyw 'LLT',ifllt
mkeyw 'Failure',iffail
mkeyw 'Success',ifsuc
data ends
code segment
extrn comnd:near, clrbuf:near, prtchr:near, outchr:near, sendbr:near
extrn cptchr:near, serini:near, pcwait:near, katoi:near
extrn cnvstr:near, getmodem:near, isdev:near, isfile:near
extrn takrd:near, takclos:near, tolowr:near, prtasz:near,strlen:near
assume cs:code, ds:data, es:nothing
; Initialize script routines before use, called as Kermit initializes.
SCPINI PROC NEAR
mov cx,scpbuflen ; (RE)INPUT buffer length
mov bx,cx ; string length, in bytes
add bx,15 ; round up
jnc scpini1 ; nc = under max size
scpini3:mov bx,0ffffh ; 64KB-16 bytes, max buffer
scpini1:mov cl,4
shr bx,cl ; convert to paragraphs (divide by 16)
scpini2:mov cx,bx ; remember desired paragraphs
mov ah,alloc ; allocate a memory block
int dos
jc scpini4 ; error, not enough memory
mov bufseg,ax ; store new segment
mov cl,4
shl bx,cl ; convert paragraphs to bytes
mov scpbuflen,bx ; new length
push es
mov es,ax ; buffer segment
xor di,di ; offset
mov cx,bx ; length in bytes
shr cx,1 ; even, do words
xor ax,ax ; null filler
cld
rep stosw ; clear the buffer
pop es
clc ; return success
ret
scpini4:mov scpbuflen,0
stc ; carry set for failure to initialize
ret
SCPINI ENDP
; Clear input buffer(s) of serial port
; Clear command
;
SCCLR PROC NEAR
mov kstatus,kssuc ; global status
mov ah,cmeol ; get a confirm
call comnd
jnc scclr1 ; nc = success
ret ; failure
scclr1: call bufclear ; clear our serial port circular buf
call clrbuf ; clear system serial port buffer too
clc
ret
SCCLR ENDP
;
; Echo a line of text to our screen
; Echo text
;
SCECHO PROC NEAR
mov ah,cmline ; get a whole line of asciiz text
mov bx,offset rdbuf ; where to store in
mov word ptr [bx],0 ; clear line
mov comand.cmblen,cmdblen ; set line capacity (length of rdbuf)
mov dx,offset echhlp ; help
call comnd
jc echo3
mov ah,cmeol
call comnd
jc echo3
mov si,offset rdbuf ; start of line
mov di,si ; convert to the same place
mov ah,script.incasv ; save current case state
push ax
mov script.incasv,0ffh ; say no case conversion
call cnvlin ; convert \numbers to binary
pop ax
mov script.incasv,ah ; recover case state
jc echo3 ; carry set means error
mov ah,prstr
mov dx,offset crlf
int dos
jcxz echo2 ; z = nothing to show
cld
echo1: lodsb ; get a source char into al
mov dl,al
mov ah,conout
int dos
loop echo1 ; get another
echo2: clc ; return success
echo3: ret ; error
SCECHO ENDP
; Extract label from command line. Store in LINE, length in slablen.
; Jump to line in Take or Macro following that label.
GOTO PROC NEAR
mov kstatus,kssuc ; global status
mov ah,cmword ; get a word
mov dx,offset line ; buffer to hold label
xor bx,bx ; no help (non-interactive command)
mov slablen,bx ; clear label holding buffer
mov comand.cmkeep,1 ; keep Take/macro open after EOF
call comnd
jnc goto1 ; nc = success
ret ; failure
goto1: mov ax,ax ; byte count
mov slablen,ax ; save count here
or ax,ax ; need contents
jz goto3 ; empty, fail
mov comand.cmkeep,1 ; keep Take file open after this call
mov ah,cmeol
call comnd
jnc goto2 ; nc = success
ret ; failure
goto2:
cmp taklev,0 ; in a Take file or Macro?
jne GETTO ; ne = yes, find the label
clc ; ignore interactive command
ret
goto3: stc
ret
; Find line starting just after ":label". Label is in variable LINE
; (length in slablen). Readjust Take read pointer to start of that line.
; Performs file search from beginning of file, popping up levels if req'd.
; Exit carry clear if success, carry set otherwise. Local worker routine.
getto proc near
push bx ; global save of bx
gett0: mov bx,takadr
cmp [bx].taktyp,0feh ; get type of take (a file?)
jne gett2 ; ne = no, a macro
; scan from start of Take file
mov eolchr,LF ; file lines end on LF
mov bx,[bx].takhnd ; rewind the file
xor cx,cx
xor dx,dx
xor al,al ; zero displacement from start of file
mov ah,lseek
int dos
jnc gett1
jmp gett20 ; c = failure
gett1: call takrd ; get a buffer of data
mov bx,takadr ; restore bx to working value
jmp short gett4
; Take a Macro
gett2: mov eolchr,CR ; Macro lines end on CR
mov cx,[bx].takbuf ; segment of macro definition
push es
mov es,cx
mov cx,es:[0] ; get string length byte
pop es
mov [bx].takcnt,cx ; set unread to full buffer (rewind)
mov [bx].takptr,2 ; set read pointer to start of text
gett4: call getch ; get a character
jc gett14 ; c = end of file, no char
cmp al,' ' ; leading white space?
je gett4 ; e = yes, read again
cmp al,TAB
je gett4
cmp al,':' ; start of label?
je gett8 ; e = yes
gett6: cmp al,eolchr ; end of line?
je gett4 ; e = yes, seek colon for label
call getch ; get a character
jc gett14 ; c = end of file, no char
jmp short gett6 ; read until end of line
gett8: mov si,offset line ; label to search for
mov cx,slablen ; its length
jcxz gett12 ; no chars to match
cmp byte ptr[si],':' ; user label starts with colon
jne gett10 ; ne = no
inc si ; skip user's colon
dec cx
jcxz gett12 ; no chars to match
gett10: call getch ; read file char into al
jc gett14 ; c = end of file
mov ah,al
cld
lodsb
call tolowr ; convert al and ah to lower case
cmp al,ah ; match?
jne gett6 ; ne = no, goto end of line
loop gett10 ; continue matching
; match obtained
call getch ; read next file character
jc gett13 ; c = end of file, no char
cmp al,' ' ; separator?
je gett12 ; e = yes, unique label found
cmp al,TAB ; this kind of separator?
je gett12 ; e = yes
cmp al,eolchr ; or end of line?
je gett13 ; e = yes
cmp al,CR ; macro eol, also file start eol pair
jne gett6 ; ne = longer label than target
gett12: call getch ; read past end of line
jc gett13 ; c = end of file, no char
cmp al,eolchr ; end of line character?
jne gett12 ; ne = no, keep reading
gett13: pop bx
clc ; return carry clear
ret ; Take pointers are ready to read line
; failed to find label, pop a level
gett14: call takclos ; close this macro/take file
cmp taklev,0 ; still in macro/take?
je gett15 ; e = no, quit
jmp gett0 ; try next level up
gett15:mov ah,prstr ; say label not found
mov dx,offset laberr ; first part of error message
int dos
mov dx,offset line
cmp line,':' ; label starts with ":"?
jne gett16 ; ne = no
inc dx ; yes, skip it
gett16: call prtasz ; print asciiz string
mov ah,prstr
mov dx,offset laberr2 ; trailer of error message
int dos
gett20: pop bx
mov kstatus,ksgen ; command status, failure
stc ; set carry for failure
ret
getto endp
GOTO ENDP
; Read char from Take buffer. Returns carry clear and char in al, or if end
; of file returns carry set. Enter with BX holding takadr. Local worker.
getch proc near
cmp [bx].takcnt,0 ; buffer empty?
jg getch2 ; g = no
cmp [bx].taktyp,0feh ; file?
jne getch1 ; ne = no, a macro
call takrd ; read another buffer
cmp [bx].takcnt,0 ; end of file?
jne getch2 ; ne = no
getch1: stc ; e = yes, exit error
ret
getch2: push si
push es
mov es,[bx].takbuf ; segment of buffer
mov si,[bx].takptr ; read a char from Take buffer
mov al,es:[si]
inc si
mov [bx].takptr,si ; move buffer pointer
dec [bx].takcnt ; decrease number of bytes remaining
pop es
pop si
clc ; return carry clear
ret
getch endp
; IF [NOT] {< }| = | > | ALARM | COUNT | FAILURE | SUCCESS
; | ERRORLEVEL \number | EQUAL string string | EXIST filespec} command
IFCMD PROC NEAR
mov notflag,0 ; assume NOT keyword is absent
ifcmd1: mov ah,cmkey ; parse keyword
mov dx,offset iftable ; table of keywords
xor bx,bx ; help is the table
call comnd
jnc ifcmd1a ; nc = success
ret ; failure
ifcmd1a:cmp bx,ifnot ; NOT keyword?
jne ifcmd2 ; ne = no
xor notflag,1 ; toggle not flag
jmp short ifcmd1 ; and get next keyword
ifcmd2: cmp bx,ifsuc ; IF SUCCESS?
jne ifcmd4 ; ne = no
cmp kstatus,kssuc ; do we have success?
je ifcmd2a ; e = yes
jmp ifcmdf ; ne = no, no jump
ifcmd2a:jmp ifcmdp ; yes
ifcmd4: cmp bx,iferr ; IF ERRORLEVEL?
jne ifcmd5 ; ne = no
jmp ifnum ; parse number to binary in line
ifcmd5: cmp bx,ifext ; IF EXIST filespec?
jne ifcmd6 ; ne = no
mov ah,cmword ; read a filespec
mov dx,offset rdbuf ; buffer for filespec
xor bx,bx
call comnd
jnc ifcmd5a ; nc = success
ret ; failure
ifcmd5a:mov ax,offset rdbuf ; isfile wants pointer in ds:ax
call isfile ; see if file exists
jc ifcmdf ; c = no
jmp ifcmdp ; yes, do following command
ifcmd6: cmp bx,iffail ; IF FAIL?
jne ifcmd7
test kstatus,not (kssuc) ; check all bits
jz ifcmdf ; z = not that condition, no jump
jmp short ifcmdp
ifcmd7: cmp bx,ifctr ; IF COUNT?
jne ifcmd8 ; ne = no
cmp taklev,0 ; in a Take file?
je ifcmdf ; e = no, fail
push bx
mov bx,takadr ; current Take structure
cmp [bx].takctr,0 ; exhausted count?
je ifcmd7a ; e = yes, dec no more ye counter
dec [bx].takctr ; dec COUNT if non-zero
cmp [bx].takctr,0 ; exhausted now?
je ifcmd7a ; e = yes
pop bx
jmp short ifcmdp ; COUNT > 0 at entry, execute command
ifcmd7a:pop bx
jmp short ifcmdf ; do not execute command
ifcmd8: cmp bx,ifmdf ; IF DEF?
jne ifcmd9 ; ne = no
jmp ifmdef ; do further parsing below
ifcmd9: cmp bx,ifalarm ; IF ALARM?
jne ifcmd10 ; ne = no
jmp ifalrm ; do further parsing below
ifcmd10:cmp bx,ifequal ; IF EQUAL?
jne ifcmd10a ; ne = no
jmp ifequ ; do further parsing below
ifcmd10a:cmp bx,iflgt ; IF LGT?
jne ifcmd10b ; ne = no
jmp ifequ
ifcmd10b:cmp bx,ifllt ; IF LLT?
jne ifcmd11 ; ne = no
jmp ifequ
ifcmd11:cmp bx,ifless ; IF <?
je ifcmd12 ; e = yes
cmp bx,ifsame ; IF =?
je ifcmd12
cmp bx,ifmore ; IF > ?
jne ifcmdf
ifcmd12:jmp ifmath
; Jump points for worker routines
; failure
ifcmdf: cmp notflag,0 ; need to apply not condition?
jne ifcmdp2 ; ne = yes, take other exit
ifcmdf2:mov ah,cmline ; fail, read and discard rest of line
mov comand.cmblen,cmdblen
mov bx,offset rdbuf
mov dx,offset discard ; say not doing anything
mov comand.cmper,1 ; don't expand variables at this time
call comnd
clc ; force success on discard of line
ret
; success (pass)
ifcmdp: cmp notflag,0 ; need to apply not condition?
jne ifcmdf2 ; ne = yes, take other exit
ifcmdp2:clc ; do command
ret
IFCMD ENDP
; Compare errlev against user number. Jump successfully if errlev >= number.
; Worker for IF [NOT] ERRORLEVEL number <command>
ifnum proc near
mov ah,cmword ; get following number
mov dx,offset rdbuf+1
mov comand.cmblen,cmdblen
mov rdbuf,'\' ; in case user forgets backslash
mov word ptr rdbuf+1,0 ; clear buffer
mov bx,offset ifnhlp ; help
call comnd
jnc ifnum1 ; nc = success
ret ; failure
ifnum1: mov si,offset rdbuf ; put text in compare buffer
cmp rdbuf+1,'\' ; did user include backslash?
jne ifnum2 ; ne = no
inc si ; yes, skip our helpful backslash
ifnum2: call katoi ; convert number to binary in ax
jc ifnum4 ; c = failed to convert a number
cmp errlev,al ; at or above this level?
jae ifnum3 ; ae = yes, succeed
jmp ifcmdf ; else fail
ifnum3: jmp ifcmdp ; jump to main command Success exit
ifnum4: mov dx,offset rdbuf+1 ; pointer to bad word
mov tempd,dx ; remember starting place for text
call strlen ; get its length
add dx,cx ; skip over current word
mov bx,dx
mov byte ptr [bx],' ' ; space, chopped by parser
inc bx ; new text goes here
xor dx,dx ; help
mov ah,cmline ; read rest of line
mov comand.cmblen,cmdblen
call comnd
jnc ifnum4a ; nc = success
ret ; failure
ifnum4a:or ax,ax ; returned byte count
jnz ifnum5 ; nz = got some
mov byte ptr[bx-1],0 ; remove space separator from above
ifnum5: mov ah,prstr
mov dx,offset ifnmsg ; error message header
int dos
mov dx,offset rdbuf+1 ; start of user text
call prtasz ; display asciiz string
mov ah,prstr
mov dx,offset ifnmsg2 ; trailer of message
int dos
jmp ifcmdf ; jump to main command Failure exit
ifnum endp
; Process IF [NOT] DEF <macro name> <command>
ifmdef proc near
mov dx,offset rdbuf+2 ; point to work buffer
mov bx,offset ifdfhlp ; help
mov comand.cmblen,cmdblen
mov ah,cmword ; get macro name
mov comand.cmper,1 ; do not react to \%x
call comnd
jnc ifmde1 ; nc = success
ret ; failure
ifmde1: mov word ptr rdbuf,ax ; store length in buffer
mov bx,offset mcctab+1 ; table of macro keywords
mov tempd,0 ; tempd = current keyword
cmp byte ptr [bx-1],0 ; any macros defined?
je ifmde9 ; e = no, failure, exit now
; match table keyword and user word
ifmde3: mov si,offset rdbuf ; pointer to user's cnt+name
mov cx,[si] ; length of user's macro name
add si,2 ; point to macro name
cmp cx,[bx] ; compare length vs table keyword
jne ifmde7 ; ne = not equal lengths, try another
push si ; lengths match, how about spelling?
push bx
add bx,2 ; point at start of keyword
ifmde4: mov ah,[bx] ; keyword char
mov al,[si] ; new text char
cmp al,'a' ; map lower case to upper
jb ifmde5
cmp al,'z'
ja ifmde5
sub al,'a'-'A'
ifmde5: cmp al,ah ; test characters
jne ifmde6 ; ne = no match
inc si ; move to next char
inc bx
loop ifmde4 ; loop through entire length
ifmde6: pop bx
pop si
jcxz ifmde10 ; z: cx = 0, found the name
; select next keyword
ifmde7: inc tempd ; number of keyword to test next
mov cx,tempd
cmp cl,mcctab ; all done? Recall, tempd starts at 0
jae ifmde9 ; ae = yes, no match
mov ax,[bx] ; cnt (keyword length from macro)
add ax,4 ; skip over '$' and two byte value
add bx,ax ; bx = start of next keyword slot
jmp short ifmde3 ; do another comparison
ifmde9: jmp ifcmdf ; jump to main command Failure exit
ifmde10:jmp ifcmdp ; jump to main command Success exit
ifmdef endp
; IF [not] ALARM hh:mm:ss command
ifalrm proc near
call chkkbd ; check keyboard for override
test status,stat_cc ; Control-C?
jz ifalr1 ; z = no
stc
ret ; yes, return failure now
ifalr1: push word ptr timhms
push word ptr timhms+2 ; save working timeouts
mov ax,word ptr alrhms
mov word ptr timhms,ax
mov ax,word ptr alrhms+2
mov word ptr timhms+2,ax ; set alarm value
call chktmo ; check for timeout
pop word ptr timhms+2 ; restore working timeouts
pop word ptr timhms
test status,stat_tmo ; tod past user time (alarm sounded)?
jnz ifalr4 ; nz = yes, succeed
; failure (not at alarm time yet)
cmp notflag,0 ; need to apply NOT condition?
jne ifalr5 ; ne = yes, take other exit
ifalr3: mov ah,cmline ; fail, read and discard rest of line
mov bx,offset rdbuf
mov comand.cmblen,cmdblen
xor dx,dx
call comnd
clc ; set command parse success
ret
; success (at or past alarm time)
ifalr4: cmp notflag,0 ; need to apply not condition?
jne ifalr3 ; ne = yes, take other exit
ifalr5: clc ; pass, do command
ret
ifalrm endp
; IF [NOT] {LLT, EQUAL, LGT} word word command
; Permits use of \number, {string}, @filespec
ifequ proc near
mov ltype,bl ; remember kind of lex test
mov comand.cmblen,cmdblen
mov ah,cmword ; get a word
mov dx,offset rdbuf ; where to store
mov rdbuf,0 ; clear first entry
mov bx,offset ifehlp1 ; help
call comnd ; ignore parse error if no text
mov si,offset rdbuf ; start of line
mov di,si ; convert to the same place
call cnvlin ; convert \numbers to binary
jc ifequ9 ; carry set means error
jcxz ifequ9 ; z = empty word
mov tempd,cx
add si,cx
inc si ; skip null terminator
mov temptr,si ; place to start second part
mov dx,si
mov word ptr[si],0 ; clear second part
mov ah,cmword ; get a word of text
mov bx,offset ifehlp2 ; help
mov comand.cmblen,cmdblen
call comnd ; ignore parse error if no text
mov si,temptr ; start of second line
mov di,si ; convert to the same place
call cnvlin ; convert \numbers to binary
jnc ifequ2a ; nc = success
ifequ9: jmp ifcmdf ; do IF cmd failure
; unequal string lengths
ifequ2a:jcxz ifequ9 ; z = empty word
mov dx,cx
cmp tempd,dx ; same lengths?
jne ifequ10 ; ne = no
jcxz ifequ9 ; both are null
mov si,offset rdbuf ; first word
mov di,temptr ; second word
push es
mov ax,ds
mov es,ax
cld
repe cmpsb ; compare while equal
pop es
jb ifequ6 ; exited on before condition
ja ifequ7 ; exited on above condition
cmp ltype,ifequal ; wanted EQUAL condition?
jne ifequ9 ; ne = no, fail
jmp ifcmdp ; else success
ifequ6: cmp ltype,ifllt ; LLT test?
jne ifequ9 ; ne = no, failed
jmp ifcmdp ; do IF cmd success
ifequ7: cmp ltype,iflgt ; LGT test?
jne ifequ9 ; ne = no, failed
jmp ifcmdp ; do IF cmd success
; unequal string lengths
ifequ10:cmp ltype,ifllt ; doing LLT?
jne ifequ11 ; ne = no
cmp tempd,dx ; first word shorter than second?
jae ifequ9 ; ae = no, fail on LLT
jmp ifcmdp ; success on LLT
ifequ11:cmp ltype,iflgt ; doing LGT?
jne ifequ9 ; ne = no, hence EQUAL and we fail
cmp tempd,dx ; first word longer than second?
jbe ifequ9 ; be = no, fail on LGT
jmp ifcmdp ; success on LGT
ifequ endp
; Worker for IF [NOT] < = > var var <command>
; var is ARGC, COUNT, ERRORLEVEL, VERSION, or a 16 bit number
ifmath proc near
mov tempa,bl ; save kind of math test here
mov temp,0 ; place to store first value
mov tempd,0 ; count times around this loop
ifmath1:mov dx,offset rdbuf+1
mov rdbuf,'\' ; in case user forgets backslash
mov word ptr rdbuf+1,0 ; clear buffer
mov bx,offset ifmhlp ; help
mov comand.cmblen,cmdblen
mov ah,cmword ; get following number
call comnd
jnc ifmath2 ; nc = success
ret ; failure
ifmath2:mov si,offset rdbuf+1 ; put text in compare buffer
mov ax,[si] ; get first two user chars
or ax,2020h ; lowercase both bytes
cmp ax,'ra' ; ARGC?
jne ifmath3 ; ne = no
xor ax,ax
cmp taklev,0 ; in a Take/macro?
je ifmath8 ; e = no, report ARGC as 0
mov bx,takadr ; current Take structure
mov ax,[bx].takargc ; get argument count
jmp short ifmath8
ifmath3:cmp ax,'re' ; ERRORLEVEL?
jne ifmath4 ; ne = no
mov al,errlev ; get errorlevel
xor ah,ah
jmp short ifmath8
ifmath4:cmp ax,'oc' ; COUNT?
jne ifmath5 ; ne = no
xor ax,ax
cmp taklev,0 ; in a Take/macro?
je ifmath8 ; e = no, report COUNT as 0
mov bx,takadr ; current Take structure
mov ax,[bx].takctr ; get COUNT
jmp short ifmath8
ifmath5:cmp ax,'ev' ; VERSION?
jne ifmath5a ; ne = no
mov ax,version ; get version such as 300
jmp short ifmath8
ifmath5a:cmp ax,'ek' ; KEYBOARD?
jne ifmath6 ; ne = no
mov ax,keyboard ; get 88 or 101 for keys on keyboard
jmp short ifmath8
ifmath6:cmp rdbuf+1,'\' ; did user include backslash?
je ifmath7 ; e = yes
dec si ; no, employ our helpful backslash
ifmath7:call katoi ; convert number to binary in ax
jc ifmathb ; c = failed to convert a number
ifmath8:cmp tempd,0 ; gotten second value yet?
ja ifmath9 ; a = yes, it is in ax
mov temp,ax ; save first value
inc tempd ; say we have been here
jmp ifmath1 ; do second argument
ifmath9:mov bl,tempa ; kind of math test
cmp bl,ifless ; "<"?
jne ifmath10 ; ne = no
cmp temp,ax ; val1 < val2?
jl ifmathp ; l = pass
jmp short ifmathf ; fail
ifmath10:cmp bl,ifsame ; "="?
jne ifmath11 ; ne = no
cmp temp,ax ; val1 = val2?
je ifmathp ; e = yes, pass
jmp short ifmathf ; fail
ifmath11:cmp temp,ax ; val2 > val1?
ja ifmathp ; a = yes, pass
ifmathf:jmp ifcmdf ; else fail
ifmathp:jmp ifcmdp ; jump to main command Success exit
ifmathb:jmp ifnum4 ; do common error complaint
ifmath endp
; SET ALARM <time, sec from now or HH:MM:SS>
SETALRM PROC NEAR
mov dx,offset line ; point to work buffer
mov word ptr line,0
mov word ptr line+2,0
mov bx,offset alrmhlp ; help
mov ah,cmword ; get macro name
call comnd
jc setal1 ; c = failure
mov ah,cmeol ; get a confirm
call comnd
jc setal1 ; c = failure
push word ptr timhms
push word ptr timhms+2 ; save working timeouts
mov si,offset line ; source pointer
call inptim ; get the timeout time, sets si
mov ax,word ptr timhms ; save time in alarm area
mov word ptr alrhms,ax
mov ax,word ptr timhms+2
mov word ptr alrhms+2,ax
pop word ptr timhms+2 ; restore working timeouts
pop word ptr timhms
clc
setal1: ret
SETALRM ENDP
; REINPUT <timeout> <match text>
; Reread material in serial port buffer, seeking a match with user's text
; pattern. If user's pattern is longer than material in buffer then read
; additional characters from the serial port. Use SCINP to do the main work.
SCREINP PROC NEAR
mov reinflg,1 ; say doing REINPUT, not INPUT
jmp short input10
SCREINP ENDP
; Input from port command, match input with text pattern
; Input [timeout] text
;
SCINP PROC NEAR
mov reinflg,0 ; say doing INPUT, not REINPUT
jmp short input10
input10:mov kstatus,kssuc
mov ah,cmline ; get a whole line of asciiz text
mov bx,offset line ; place to put text
mov dx,offset inphlp ; help message
call comnd ; get the pattern text
jnc input11 ; nothing, complain
ret ; failure
input11:mov ah,cmeol
call comnd
jnc input12
ret
input12:cmp reinflg,0 ; Input command?
jne input1 ; ne = no, Reinput
cmp taklev,0 ; are we in a Take file?
je input0 ; e = no, display linefeed
cmp flags.takflg,0 ; are Take commands being echoed?
je input1 ; e = no, skip display
input0: cmp script.inecho,0 ; Input echo off?
je input1 ; e = yes
mov al,lf ; next line
call scdisp ; display the char
input1: call serini ; initialize the system's serial port
jc input1a ; c = failure
mov status,stat_unk ; clear status flag
mov si,offset line ; source pointer
call inptim ; get the timeout time, sets si
jnc input1b ; nc = legal time value or none
input1a:jmp input5 ; else fail on error
input1b:mov di,offset line ; put text in compare buffer
call cnvlin ; convert \numbers in buf line
mov inplen,cx ; cx = number of bytes in final string
mov parmsk,0ffh ; parity mask, assume 8 bit data
mov di,portval
cmp [di].parflg,parnon ; parity is none?
je input1c ; e = none
mov parmsk,07fh ; else strip parity (8th) bit
input1c:mov di,offset line
mov temptr,di ; pointer to pattern char
mov temptr2,di ; and we need pointer to end of string
add temptr2,cx ; offset of end of string
; setup reinput read pointer & count
mov ax,bufwtptr ; where next new char goes
mov bufpkptr,ax ; set peek-read pointer at oldest char
mov ax,scpbuflen ; length of the buffer
mov bufpkcnt,ax ; always look back one full buffer
; see if a pattern needs matching
cmp inplen,0 ; empty pattern? (cnvlin sets cx=cnt)
jne input4 ; ne = not empty
cmp reinflg,0 ; Input command?
je input3 ; e = yes, read and discard chars
jmp input5 ; reinput, just exit timeout
; empty. read, display, and discard
input3: call chkkbd ; check keyboard
test status,stat_cc ; did user type control-c?
jnz input3b ; nz = yes, quit
test status,stat_cr ; did user type cr? [js]
jz input3a ; z = no
or status,stat_tmo ; force timeout status too
jmp short input5 ; nz = yes, return timeout failure
input3a:call chktmo ; check timeout
test status,stat_tmo
input3b:jnz input5 ; nz = timed out, quit
call bufread ; read from serial port buffer into al
jmp short input3 ; loop until timeout, exit timeout
; start main read and compare loop
input4: mov di,temptr ; pointer to current pattern char
cmp di,temptr2 ; at end of pattern?
jae inputx ; ae = yes, return success
call chkkbd ; check keyboard
test status,stat_cc ; did user type Control-C?
jnz input5 ; nz = yes, quit
test status,stat_cr ; did user type cr? [js]
jz input4a ; z = no
or status,stat_tmo ; force timeout status too
jmp short input5 ; nz = yes, return success [js]
input4a:test status,stat_tmo+stat_ok ; user override/timeout on last read
jnz input5 ; nz = timed out, quit
cmp reinflg,0 ; Input command?
jne input4b ; ne = no, a reinput cmd
call bufread ; read from serial port buffer into al
jc input4 ; c = nothing there, keep looking
jmp short input4c ; analyze character
input4b:call peekbuf ; reinput: peek-read from buffer
jnc input4c ; nc = got a character into al
test status,stat_tmo ; timeout (or examined all chars)?
jz input4 ; z = no, keep trying
jnz input5 ; nz = timeout getting a character
; got a char from buffer/port
input4c:cmp al,'a' ; candidate for case conversion? [js]
jb input4d ; b = no [js]
cmp al,'z' ; in lower case set? [js]
ja input4d ; a = no [js]
and al,script.incasv ; apply case conversion mask
input4d:mov di,temptr
mov ah,byte ptr [di] ; get current pattern char again
call matchr ; al=rcvd, ah=pattern, do they match?
jc inpm ; c = no match, try substring
inc temptr ; matched, point to next pattern char
jmp short input4
input5: or errlev,ksrecv ; set RECEIVE failure condition
or fsta.xstatus,ksrecv ; set status
or kstatus,ksrecv
cmp reinflg,0 ; Input command?
jne input6 ; ne = no
jmp squit ; exit failure: timeout or Control-C
input6: jmp squit1 ; skip timeout message, if any
inputx: clc ; return success
ret
; See if a trailing-subset of the matched chars + new port char can match
; the beginning part of the pattern. That is, if we were to simply "forget"
; the oldest of the matched chars and slide left the apparent port string
; then could we eventually find a match? Example: "Input 10 memema"
; gives the pattern of "memema"; suppose the received chars were "mememema".
; Forgetting one left-most rcv'd char at a time (two in this case) finally
; yields a match, from which we should continue to compare fresh port chars
; with successive pattern chars until either they match through all pattern
; chars or we encounter another break. If there is a later break, repeat this
; algorithm.
; Since we really have only the latest char from the port then pointers to
; the matched pattern chars are used to mimic the earlier received chars:
; they must have been identical to produce a match to date. The quick way
; to "forget" oldest received chars is to scan backward through the matched
; pattern chars looking for the current port char; if the first such find does
; not yield a matching substring then look back further.
; no or partial match then break
; di = temptr = pattern break char
; al = port char causing break
; di - offset line = # chars matched thus far
; avoid cpu-brand side effects with "repne scasb"
inpm: mov tempa,al ; save port char here
inpm1: mov tempd,di ; pattern break loc, where matching failed
mov cx,di ; char at di does not match current port char
sub cx,offset line ; compute count of matched bytes
jcxz inpm4 ; z = 0 = mismatch on the initial pattern char
mov al,tempa ; port char to find (in case we looped here)
inpm2: dec di ; back up one pattern char
mov ah,byte ptr [di]; current pattern character to consider
call matchr ; is port char = earlier pattern char? [js]
jnc inpm3 ; nc = equal values, go construct substring
loop inpm2 ; do cx times, max. (length of match to date)
jmp short inpm4 ; get here when there are no matches [js]
inpm3: mov bx,tempd ; get last break location
sub bx,di ; displacement = break - new find of port char
mov tempd,di ; remember new location of a port-like char
; cx has number of chars in test substring
dec cx ; matched one char already [jrs]
jcxz inpm3a ; is there anything left? [jrs]
call matstr ; does this substring match the pattern?
jc inpm1 ; c = no match, try making substring smaller
inpm3a: mov di,tempd ; sub-string matched. Use this shorter match
mov temptr,di ; set di for exit (matstr messes up di)
inc temptr ; matched, point to next pattern char
jmp input4 ; continue with fresh port info
inpm4: mov temptr,offset line; complete failure, restart scanning
jmp input4 ; get something from the port
; worker for SCINP
; compare strings. One starts at offset line, the other starts bx bytes later.
; cx = # chars to compare. Return carry clear if match, else carry set.
matstr: mov si,offset line ; start of pattern string
matstr1:mov ah,byte ptr [si] ; pattern char
mov al,byte ptr [si+bx] ; "old port char" (same as pattern char)
call matchr ; check match of these two characters
jc matstr2 ; c = no match (exit with carry flag set)
inc si ; match, consider next pair
loop matstr1 ; consider rest of substring (cx is counter)
clc ; clear c bit (substrings do match)
matstr2:ret ; preserves flags (c set = no match)
; worker for SCINP
; compare single characters, one in ah and the other in al. Allow the 0ffh
; wild card to match CR and LF individually. Return carry clear if match,
; or carry set if they do not match. Registers preserved.
matchr: cmp ah,al ; do these match?
je matchr6 ; e = yes
cmp ah,0ffh ; the match cr/lf indicator?
je matchr2 ; e = yes
cmp al,0ffh ; the match cr/lf indicator?
jne matchr5 ; ne = no match at all.
matchr2:push ax ; save both chars again
and ah,al ; make a common byte for testing
cmp ah,cr
je matchr4 ; e = cr matches 0ffh
cmp ah,lf
je matchr4 ; e = lf matches 0ffh
pop ax ; recover chars
matchr5:stc ; set carry (no match)
ret
matchr4:pop ax ; recover chars
matchr6:clc ; clear carry (match)
ret
SCINP ENDP
;
; Pause for the specified number of seconds or until a time of day
; Pause [seconds or hh:mm:ss]
;
SCPAU PROC NEAR
mov kstatus,kssuc
mov ah,cmword ; get a word (number)
mov dx,offset line ; where to store it
mov byte ptr line,0 ; terminate line incase no text
mov bx,offset ptshlp ; help msg
call comnd
jc scpau1 ; c = failure
mov si,offset line ; source pointer
call inptim ; parse pause time (or force default)
jc scpau1 ; c = bad time value
mov wtemp,0 ; no modem status to detect
jmp swait4 ; finish in common code
scpau1: ret ; return command failure
SCPAU ENDP
;
; Wait for the indicated signal for the specified number of seconds or tod
; WAIT [seconds] \signal where \signal is \cd, \dsr modem status lines.
; Use INPUT-TIMEOUT ACTION for failures.
;
SCWAIT PROC NEAR
mov kstatus,kssuc
mov ah,cmword ; get a word (number)
mov dx,offset line ; where to store it
mov byte ptr line,0 ; terminate line incase no text
mov bx,offset ptshlp ; time help msg
call comnd
jc swait1a ; c = failure
mov wtemp,0 ; clear modem status test byte
mov si,offset line ; source pointer
call inptim ; parse pause time (or force default)
jc swait1a ; c = bad time value
mov di,offset line ; put text in compare buffer
call cnvlin ; convert \numbers in buf line
mov si,di ; code below uses si
jnc swait1 ; nc = no error
swait1a:ret ; else return on error
swait1: mov ah,cmword ; get optional modem signal word(s)
mov dx,offset line
mov bx,offset wthlp ; modem signal help
call comnd
jc swait1a ; c = failure
mov si,offset line
mov cx,ax ; returned byte count
swait1b:or cx,cx ; number of chars to examine
jle swait4 ; le = none
cld
lodsb ; get a character
dec cx ; reduce count remaining
cmp al,'\' ; backslash signal introducer?
je swait1b ; e = yes, skip it
cmp cx,1 ; at least two chars in signal?
jl swait3 ; l = no
mov ax,[si-1] ; get first two characters
or ax,2020h ; upper case to lower, two chars
cmp ax,'dc' ; carrier detect?
jne swait2 ; ne = no, try next signal
or wtemp,modcd ; look for the CD bit
inc si ; skip this field and separator
dec cx ; two less chars left in the line
jmp short swait1b ; continue the scan
swait2: cmp ax,'sd' ; data set ready?
jne swait3 ; ne = no
mov al,[si+1] ; third letter
or al,20h ; to lower case
cmp al,'r' ; r for dsr?
jne swait3 ; ne = no
or wtemp,moddsr ; look for the DSR bit
add si,2 ; skip this field and separator
sub cx,2 ; three less chars left in the line
swait3: cmp ax,'tc' ; clear to send?
jne swait3a ; ne = no
mov al,[si+1] ; third letter
or al,20h ; to lower case
cmp al,'s' ; r for dsr?
jne swait3a ; ne = no
or wtemp,modcts ; look for the CTS bit
add si,2 ; skip this field and separator
sub cx,2 ; three less chars left in the line
swait3a:jmp short swait1b ; continue the scan
; SWAIT4 is used by PAUSE command
SWAIT4: mov ah,cmeol ; get command confirmation
call comnd
jnc swait4a
ret ; c set is failure
swait4a:cmp taklev,0 ; are we in a Take file
je swait5 ; e = no, print linefeed
cmp flags.takflg,0 ; are commands being echoed
je swait6 ; e = no, skip this
swait5: cmp script.inecho,0 ; Input echoing off?
je swait6 ; e = yes
mov al,lf ; next line
call scdisp ; display the char
swait6: call serini ; initialize the system's serial port
jc swait9 ; c = failure
mov status,stat_unk ; clear status flag
push si
mov parmsk,0ffh ; parity mask, assume 8 bit data
mov si,portval
cmp [si].parflg,parnon ; parity is none?
pop si
je swait7 ; e = none
mov parmsk,07fh ; else strip parity (8th) bit
swait7: cmp wtemp,0 ; anything to be tested?
je swait7a ; e = no, just do the wait part
call getmodem ; modem handshake status to AL
and al,wtemp ; keep only bits to be tested
cmp al,wtemp ; check selected status bits
jne swait7a ; ne = not all selected bits match
clc ; all match. take successful exit
ret
swait7a:call chkport ; get and show any new port char
call chkkbd ; check keyboard
test status,stat_cc ; control-c?
jnz swait9 ; nz = yes, quit
call chktmo ; check tod for timeout
test status,stat_tmo+stat_ok ; timeout or user override?
jz swait7 ; z = no, continue to wait
cmp wtemp,0 ; were we waiting on anything?
jne swait9 ; ne = yes, timeout = failure
clc ; else timeout = success
ret
swait9: or errlev,ksuser ; set user intervention error condx
or fsta.xstatus,ksuser ; set status
or kstatus,ksuser
jmp squit ; take error exit
SCWAIT ENDP
; Output line of text to port, detect \b and \B as commands to send a Break
; on the serial port line.
; Output text, display up to 100 received chars while doing so.
SCOUT PROC NEAR
mov kstatus,kssuc
mov ah,cmline ; get a whole line of asciiz text
mov bx,offset line ; store text here
mov dx,offset outhlp ; help message
call comnd
jnc outp0d ; nc = success
ret ; failure
outp0d: cmp taklev,0 ; is this being done in a Take file?
je outpu0 ; e = no, display linefeed
cmp flags.takflg,0 ; are commands being echoed?
je outp0a ; e = no, skip the display
outpu0: cmp script.inecho,0 ; Input echoing off?
je outp0a ; e = yes
mov al,lf ; next line
call scdisp ; display the char
outp0a: mov al,spause ; wait three millisec or more
add al,3
xor ah,ah
call pcwait ; breathing space for HDX systems
call serini ; initialize the system's serial port
jnc outp0c ; nc = success
or errlev,kssend ; set SEND failure condition
or fsta.xstatus,kssend ; set status
or kstatus,kssend
jmp squit
outp0c: mov status,stat_unk ; clear status flag
mov parmsk,0ffh ; parity mask, assume 8 bit data
mov si,portval
cmp [si].parflg,parnon ; parity is none?
je outp0b ; e = none
mov parmsk,07fh ; else strip parity (8th) bit
outp0b: mov si,portval ; serial port structure
mov bl,[si].ecoflg ; Get the local echo flag
mov lecho,bl ; our copy
mov si,offset line ; get start of line
mov di,offset line ; put results in the same place
mov ah,script.incasv ; save current case state
push ax
mov script.incasv,0ffh ; say no case conversion
call cnvlin ; convert \numbers to binary
pop ax
mov script.incasv,ah ; recover case state
jnc outpu1 ; nc = no error
ret ; return on error
outpu1: mov temptr,offset line ; save pointer here
mov tempd,cx ; save byte count here
mov ttyact,1 ; say interactive style output
outpu2: cmp tempd,0 ; are we done?
jg outpu2a ; g = not done yet
mov ttyact,0 ; reset interactive output flag
clc ; return success
ret
outpu2a:mov si,temptr ; recover pointer
cld
lodsb ; get the character
dec tempd ; one less char to send
mov temptr,si ; save position on line
mov tempa,al ; save char here for outchr
mov retry,0 ; number of output retries
cmp al,5ch ; backslash?
jne outpu4d ; ne = no
cmp byte ptr [si],'b' ; "\b" for Break?
je outpu4c ; e = yes
cmp byte ptr [si],'B' ; "\B" ?
jne outpu4d ; ne = no
outpu4c:inc temptr ; move scan ptr beyond "\b"
dec tempd
call sendbr ; call msx send-a-break procedure
jmp short outpu5 ; resume beyond echoing
outpu4d:inc retry ; count output attempts
cmp retry,maxtry ; too many retries?
jle outpu4g ; le = no
or errlev,kssend ; set SEND failure condition
or fsta.xstatus,kssend ; set status
or kstatus,kssend
jmp squit ; return failure
outpu4g:mov ah,tempa ; outchr gets fed from ah
call outchr ; send the character to the port
jc outpu4d ; failure to send char
cmp lecho,0 ; is Local echo active?
je outpu5 ; e = no
mov al,tempa ;
test flags.capflg,logses ; is capturing active?
jz outp4b ; z = no
push ax ; save char
call cptchr ; give it captured character
pop ax ; restore character and keep going
outp4b: cmp script.inecho,0 ; Input echo off?
je outpu5 ; e = yes
call scdisp ; echo character to the screen
;
outpu5: mov tempa,100+1 ; wait for max 100 chars in/out [dan]
outpu5a:mov cx,10 ; reset retry counter
outpu5b:push cx
call chkkbd ; check keyboard for interruption
pop cx
test status,stat_cc ; control c interrupt?
jnz outpu6 ; nz = yes, quit now
cmp script.inecho,0 ; Input echo off?
je outpu5c ; e = yes, skip port reading/display
dec tempa ; reached maximum chars in yet? [dan]
jz outpu5c ; z = yes, send character anyway [dan]
push cx
call chkport ; check for char at serial port
pop cx
test status,stat_ok ; and put any in buffer
jnz outpu5a ; nz = have a char, look for another
mov ax,1 ; wait 1 millisec between rereads
push cx ; protect counter
call pcwait
pop cx
dec cx ; count down retries
jge outpu5b ; ge = keep trying
outpu5c:jmp outpu2 ; no more input, resume command
outpu6: or errlev,kssend ; set SEND failure condition
or fsta.xstatus,kssend ; set status
or kstatus,kssend
mov ttyact,0 ; reset interactive output flag
jmp squit ; quit on control c
SCOUT ENDP
; Raw file transfer to host (strips linefeeds)
; Transmit filespec [prompt]
; Optional prompt is the single char expected from the host to ACK each line.
; Default prompt is a script.xmitpmt (linefeed) or a carriage return from us.
;
SCXMIT PROC NEAR
mov kstatus,kssuc
mov ah,cmword ; get a filename, asciiz
mov dx,offset line ; where to store it
mov bx,offset xmthlp ; help message
call comnd
jnc xmit0c ; nc = success
ret ; failure
xmit0c: mov ah,cmword ; get a prompt string, asciiz
mov script.xmitpmt,CR ; preset default XMIT prompt
mov dx,offset line+80 ; where to keep it (end of "line")
mov line+80,0 ; clear and add terminator
mov bx,offset pmthlp ; Help in case user types "?".
call comnd
jnc xmit0d ; nc = success
ret ; failure
xmit0d: mov ah,cmeol ; confirm
call comnd
jnc xmit0e
ret
xmit0e: cmp line,0 ; filename given?
je xmit0a ; e = no
mov si,offset line+80 ; convert possible numeric prompt
or si,si ; anything given?
jz xmit0 ; z = no, use default
call katoi ; convert number to binary, if number
jnc xmit0b ; nc = got number
mov al,line+80 ; get ascii char from user's prompt
xmit0b: mov script.xmitpmt,al ; prompt
xmit0: mov dx,offset line ; point to filename
mov ah,open2 ; DOS 2 open file
xor al,al ; open for reading
int dos
mov fhandle,ax ; store file handle here
mov temp,0 ; counts chars/line
jnc xmit1 ; nc = successful opening
xmit0a: mov ah,prstr ; give file not found error message
mov dx,offset xfrfnf
int dos
or errlev,kssend ; set SEND failure condition
or fsta.xstatus,kssend ; set status
or kstatus,kssend
jmp squit ; exit failure
xmitx: mov ah,prstr ; error during transfer
mov dx,offset xfrrer
int dos
xmitx2: mov bx,fhandle ; file handle
mov ah,close2 ; close file
int dos
call bufclear ; clear script buffer
call clrbuf ; clear local serial port buffer
or errlev,kssend ; set SEND failure condition
or fsta.xstatus,kssend ; set status
or kstatus,kssend
jmp squit ; exit failure
;
xmity: mov bx,fhandle ; file handle
mov ah,close2 ; close file
int dos
call bufclear ; clear buffers
call clrbuf
clc ; and return success
ret
xmit1: call serini ; initialize serial port
jnc xmit1b ; nc = success
or errlev,kssend ; set SEND failure condition
or fsta.xstatus,kssend ; set status
or kstatus,kssend
jmp squit
xmit1b: call bufclear ; clear script input buffer
call clrbuf ; clear serial port buffer
mov status,stat_unk ; clear status flag
mov parmsk,0ffh ; parity mask, assume 8 bit data
mov si,portval
cmp [si].parflg,parnon ; parity is none?
je xmit1a ; e = none
mov parmsk,07fh ; else strip parity (8th) bit
xmit1a: mov bl,[si].ecoflg ; get the local echo flag
mov lecho,bl ; our copy
mov dx,offset crlf ; display cr/lf
mov ah,prstr
int dos
xmit2: mov dx,offset line ; buffer to read into
mov cx,linelen ; # of bytes to read
mov ah,readf2 ; read bytes from file
mov bx,fhandle ; file handle is stored here
int dos
jnc xmit2a ; nc = success
jmp xmitx ; exit failure
xmit2a: mov cx,ax ; number of bytes read
jcxz xmity ; z = none, end of file
;
mov si,offset line ; buffer for file reads
cld
xmit3: lodsb ; get a byte
cmp al,ctlz ; is this a Control-Z?
jne xmit3a ; ne = no
cmp flags.eofcz,0 ; ignore Control-Z as EOF?
jne xmity ; ne = no, we are at EOF
xmit3a: push si ; save position on line
push cx ; and byte count
cmp al,cr ; CR, end of line?
jne xmit3b ; ne = no
cmp temp,0 ; chars sent in this line, any?
ja xmit3c ; a = sent some
cmp script.xmitfill,0 ; fill empty lines?
je xmit3c ; e = no, send the cr
mov al,script.xmitfill ; empty line fill char
pop cx
pop si
dec si ; backup read pointer to CR again
inc cx ; count filler as line information
push si
push cx
jmp short xmit3c
xmit3b: cmp al,lf ; line feed?
jne xmit3c ; ne = no
cmp script.xmitlf,0 ; send LF's?
je xmit7 ; e = no, don't send it
mov temp,-1 ; -1 so inc returns 0 after send
xmit3c: push ax ; save char around outchr call
mov retry,0 ; clear retry counter
xmit4f: pop ax ; recover saved char
push ax ; and save it again
mov ah,al ; outchr wants char in ah
inc retry ; count number of attempts
cmp retry,maxtry ; too many retries?
jle xmit4g ; le = no
or status,stat_cc ; simulate control-c abort
pop ax ; clean stack
xor al,al ; clear char
jmp short xmita ; and abort transfer
xmit4g: call outchr ; send the character to the port
inc temp ; count chars sent in this line
jc xmit4f ; c failed, try again
xmit4h: pop ax ; recover saved char
cmp lecho,0 ; is local echoing active?
je xmit5 ; e = no
test flags.capflg,logses ; capturing active?
jz xmit4a ; z = no
call cptchr ; give it the character just sent
xmit4a: call scdisp ; display char on screen
xmit5: cmp al,cr ; did we send a carriage return?
je xmit8 ; e = yes, time to check keyboard
xmit7: pop cx
pop si
dec cx
or cx,cx
jle xmit7a ; le = finished this line
jmp xmit3 ; finish this buffer full
xmit7a: jmp xmit2 ; read next buffer
xmit8: test status,stat_cc ; Control-C seen?
jnz xmita ; nz = yes
mov temp,0 ; say starting new char/line count
call chkkbd ; check keyboard (returns char in al)
test status,stat_ok ; have a char?
jnz xmita ; nz = yes
cmp script.xmitpmt,0 ; is prompt char a null?
jne xmit8b ; ne = no
call bufread ; check for char from serial port buf
jnc xmit8 ; nc = a char, read til none
jmp short xmit7 ; continue transfer
xmit8b: call bufread ; check for char from serial port buf
jc xmit8 ; c = none
cmp al,script.xmitpmt ; is port char the ack?
jne xmit8 ; ne = no, just ignore the char
jmp short xmit7 ; yes, continue transfer
xmita: test status,stat_cc ; control-c?
jnz xmitc ; nz = yes
test status,stat_cr ; a local ack?
jz xmit8 ; no, ignore local char
mov dx,offset crlf ; display cr/lf
mov ah,prstr
int dos
jmp xmit7 ; continue transfer
xmitc: pop cx ; Control-C, clear stack
pop si ; ...
mov dx,offset xfrcan ; say canceling transfer
mov ah,prstr
int dos
mov flags.cxzflg,0 ; clear Control-C flag
jmp xmitx2 ; ctrl-c, quit
SCXMIT ENDP
;;;;;;;;;;;;;;;;;; local support procedures ;;;;;;;;;;
;
;worker: copy line from si to di, converting \nnn strings to single chars
; returns carry set if error, else carry clear. Detects leading at-sign
; as an indicator to read command file for one line of text; command files
; may be nested to a depth of 100.
; Items of the form \chars which are not numbers are copied verbatium
; to the output string (ex: \a is copied as \a). The string is first trimmed
; of trailing spaces, then the possible curly brace delimiter pair is
; removed, and finally \numbers are converted to binary. [jrd]
cnvlin proc near
push tempd
push es
push si ; source ptr
push di ; destination ptr
push ds
pop es ; use data segment for es:di
mov tempd,0 ; count indirection depth
cnvln0: cmp tempd,100 ; limit to 100 deep
jbe cnvln0a ; be = not too deep yet
jmp cnvln8 ; too deep, quit
cnvln0a:cld
xor cx,cx ; initialize returned byte count
lodsb ; get the first character
cmp al,40h ; at-sign indirection?
je cnvln5 ; e = yes, open the file
dec si ; no, push back char just read
call cnvstr ; convert string's curly braces
cnvln1: xor ah,ah ; clear high byte of number
call katoi ; get a char into al, convert number
jnc cnvln4 ; nc = binary number converted
cmp al,0ffh ; cr/lf wild card?
je cnvln4 ; e = yes, store it
or al,al ; end of line?
jnz cnvln3 ; nz = no
jmp cnvlnx ; yes, exit now
cnvln3: cmp al,'a' ; candidate for conversion? [js]
jb cnvln4 ; b = no
cmp al,'z' ; still in lower case set? [js]
ja cnvln4 ; a = no
and al,script.incasv ; else apply case conversion mask
cnvln4: stosb ; save the char
inc cx ; and count it
or ah,ah ; was number larger than one byte?
jz cnvln1 ; z = no
xchg ah,al ; put high byte into al
stosb ; store it too
inc cx ; count storage
jmp short cnvln1 ; read more
cnvln5: mov dx,si ; get filename ptr from source line
push si
inc tempd ; count indirection depth
mov cx,64 ; max length of a filename.
cnvln5a:cmp byte ptr [si],' ' ; whitespace or control code?
jbe cnvln5b ; be = yes, found termination
inc si ; else look at next char
loop cnvln5a ; limit search
cnvln5b:mov byte ptr [si],0 ; make asciiz
pop si
mov ah,open2 ; DOS 2 open file
xor al,al ; open for reading
int dos
mov word ptr fhandle,ax ; store file handle
jnc cnvln7 ; nc = open ok, read from file
mov ah,prstr
mov dx,offset indmis ; file open error msg
int dos
xor cx,cx ; say zero bytes read
pop di ; destination ptr
pop si ; source ptr
pop es
pop tempd
stc ; set c bit, failure
ret
cnvln7: mov bx,word ptr fhandle ; file handle
mov cx,linelen ; # of bytes to read
mov ah,ioctl ; ioctl, is this the console device?
xor al,al ; get device info
int dos
and dl,81h ; ISDEV and ISCIN bits needed together
cmp dl,81h ; Console input device?
jne cnvln7d ; ne = no, use regular file i/o
push ds
pop es ; set es:di to data segment
push di ; save starting pointer
cnvln7b:mov ah,coninq ; read console, no echo
int dos
stosb
cmp al,cr ; end of the line yet?
loopne cnvln7b ; keep reading
mov byte ptr [di],0 ; insert terminator
pop di ; recover starting pointer
mov dx,di ; simulate read file read
mov ax,linelen
sub ax,cx ; ax = number of chars read
jmp short cnvln7e ; close file, finish processing
cnvln7d:mov dx,di ; destination ptr
mov byte ptr [di],0 ; insert null terminator, clears line
mov ah,readf2 ; DOS 2 read from file
int dos
cnvln7e:pushf ; save flags
push ax ; save byte count read
mov ah,close2 ; close file (wanted just one line)
int dos
pop ax
popf ; recover flags now
jc cnvln8 ; c = error
mov cx,ax ; ax = number of bytes read
jcxz cnvln8a ; cx = z = no bytes read
mov al,cr ; look for cr as terminator
cld
repne scasb ; scan while not a cr and cx not zero
jne cnvln7a ; ne = no cr found
dec di ; point at cr
cnvln7a:mov byte ptr [di],0 ; plant terminator on the cr
; or after last read char, if no cr.
pop di ; get original destination ptr
push di ; and save it again
mov si,dx ; new source = this line
; go convert text, as necessary, and
jmp cnvln0 ; allow nested indirection
cnvln8: mov ah,prstr
mov dx,offset inderr ; error reading file message
int dos
cnvln8a:xor cx,cx ; say zero bytes read
pop di
pop si
pop es
pop tempd
stc ; set carry for failure
ret ; and do a real return
cnvlnx: pop di ; destination ptr
pop si ; source ptr
pop es
pop tempd
clc ; clear c bit, success
ret
cnvlin endp
;
; worker: read the number of seconds to pause or timeout
; returns time of day for timeout in timhms, and next non-space or
; non-tab source char ptr in si. Time is either elapsed seconds or
; a specific hh:mm:ss, determined from context of colons being present.
; Last form can be abbreviated as hh:[mm[:ss]]. Returns carry set if
; hh:mm:ss form has bad construction (invalid time).
inptim proc near
push ax
push bx
push cx
push dx
push di
cld ; decode pure seconds construction
mov di,si ; remember source pointer
mov cx,10 ; multiplier
mov bx,script.indfto ; no numbers yet, use default-timeout
mov al,byte ptr[si]
cmp al,':' ; stray hh:mm:ss separator?
je inptm8 ; e = yes
cmp al,'9' ; start with numeric input?
ja inptm4 ; a = no, use default time
cmp al,'0' ; ditto
jb inptm4
xor ah,ah ; source char holder
xor bx,bx ; accumulated sum
inptm1: mov al,byte ptr[si] ; get a byte into al
cmp al,':' ; hh:mm:ss construction?
je inptm8 ; e = yes
sub al,'0' ; remove ascii bias
cmp al,9 ; numeric?
ja inptm4 ; a = non-numeric, exit loop, bx = sum
xchg ax,bx ; put sum into ax, char in bl
mul cx ; sum times ten
xchg ax,bx ; put char into al, sum in bx
add bx,ax ; add to sum
inc si ; next char
jmp short inptm1 ; loop thru all chars
inptm4: cmp bx,12*60*60 ; half a day, in seconds
jb inptm5 ; b = less than
jmp inptm13 ; more than, error
inptm5: push si ; save ending scan position for return
mov timout,bx ; # seconds of timeout desired
mov ah,gettim ; read DOS tod clock
int dos
mov timhms[0],ch ; hours
mov timhms[1],cl ; minutes
mov timhms[2],dh ; seconds
mov timhms[3],dl ; hundredths of seconds
mov bx,2 ; start with seconds field
inptm6: mov ax,timout ; our desired timeout interval
add al,timhms[bx] ; add current tod digit to interval
adc ah,0
xor dx,dx ; clear high order part thereof
mov cx,60 ; divide by 60
div cx ; compute number of minutes or hours
mov timout,ax ; quotient
mov timhms[bx],dl ; put remainder in timeout tod digit
dec bx ; look at next higher order time field
or bx,bx ; done all time fields?
jge inptm6 ; ge = no
cmp timhms[0],24 ; normalize hours
jl inptm7 ; l = not 24 hours
sub timhms[0],24 ; discard part over 24 hours
inptm7: pop si ; return ptr to next source char
jmp short inptm11 ; trim trailing whitespace
inptm8: ; decode hh:[mm[:ss]] to timhms
mov si,di ; recall starting source pointer
mov word ptr timhms[0],0 ; clear time out tod
mov word ptr timhms[2],0
xor bx,bx ; three groups possible
inptm9: mov dl,byte ptr[si] ; get a char
cmp dl,':' ; field separator?
je inptm10 ; e = a separator, step fields
sub dl,'0' ; remove ascii bias
cmp dl,9
ja short inptm11 ; a = failure to get expected digit
mov al,timhms[bx] ; get sum to al
mov ah,10
mul ah ; sum times ten
add al,dl ; sum = 10 * previous + current
mov timhms[bx],al ; current sum
cmp timhms[bx],60 ; more than legal?
jae inptm13 ; ae = illegal
or bx,bx ; doing hours?
jnz inptm9a ; nz = no, min or sec
cmp timhms[bx],24 ; more than legal?
jae inptm13 ; ae = illegal
inptm9a:inc si ; next char
jmp short inptm9 ; continue analysis
inptm10:inc bx ; point to next field
inc si ; next char
cmp bx,2 ; last subscript to use (secs)
jbe inptm9 ; be = get more text
inptm11:cmp byte ptr [si],spc ; examine break char, remove spaces
jne inptm12 ; ne = no, stay at this char
inc si ; look at next char
jmp short inptm11 ; continue scanning off white space
inptm12:clc ; carry clear for success
jnc inptm14
inptm13:stc ; carry set for illegal value
inptm14:pop di ; return with si beyond our text
pop dx
pop cx
pop bx
pop ax
ret
inptim endp
; worker: display the char in al on screen
; use caret-char notation for control codes
scdisp proc near
push dx
push ax
mov ah,conout ; our desired function
test flags.remflg,d8bit ; show all 8 bits?
jnz scdisp0 ; nz = yes
and al,7fh ; apply 7 bit display mask
scdisp0:or al,al ; null?
jz scdis2 ; z = yes, ignore
cmp al,del ; delete code?
je scdis2 ; e = yes, ignore
cmp al,spc ; control char?
jae scdis1 ; ae = no, display as-is
cmp al,cr ; carriage return?
je scdis1 ; e = yes, display as-is
cmp al,lf ; line feed?
je scdis1
cmp al,tab ; horizontal tab?
je scdis1
cmp al,bell ; bell?
je scdis1
cmp al,bs ; backspace?
je scdis1
cmp al,escape ; escape?
je scdis1
or al,40h ; control code to printable char
push ax
mov dl,5eh ; display caret first
int dos
pop ax
scdis1: mov dl,al ; the char to be displayed
int dos
scdis2: pop ax
pop dx
ret
scdisp endp
; workers
; Circular buffer for data from serial port. Written by Joe R. Doupnik
; Entry points -
; bufread: read serial port for latest char (invokes bufwrite, sets
; status), get a char into al, return carry set if none.
; bufwrite: put a char from al into buf. If this overwrites an unread
; character then: we lose the old char, the read pointer
; is moved to the next oldest unread char, and the
; number of chars in the buffer is decreased by one.
; bufclear: empties the buffer.
; The buffer is prtbuf, of size scpbuflen bytes. Internally, integer bufcnt
; holds the number of buffer locations occupied, pointer bufrdptr is the
; offset of the char to be read, pointer bufwtptr is the offset of the
; place to store the next incoming char.
;
bufclear proc near
xor ax,ax ; create a zero
mov bufcnt,ax ; clear count of bytes in buffer
mov bufrdptr,ax ; move read pointer to start of buf
mov bufwtptr,ax ; move write pointer to start of buf
mov cx,scpbuflen
push es ; physically clear the buffer
push di
mov ax,bufseg ; segment of port buffer
mov es,ax
xor al,al ; write scpbuflen nulls
xor di,di
cld
shr cx,1 ; do an odd byte now
jnc bufcle1 ; nc = no odd byte
stosb
bufcle1:rep stosw ; do double bytes (words)
pop di
pop es
ret
bufclear endp
bufread proc near
call chkport ; get any oldest char from port
call chktmo ; check tod for timeout
cmp bufcnt,0 ; empty buffer?
jne bufrd1 ; ne = no
stc ; yes, set carry flag (no char)
ret ; and quit (chkport sets status)
bufrd1: push si
push es
mov si,bufseg ; get buffer segment
mov es,si
mov si,bufrdptr
mov al,es:[si] ; extract a char into al
inc bufrdptr ; move pointer to next byte
dec bufcnt ; say have extracted a char
mov si,scpbuflen
cmp bufrdptr,si ; beyond end?
jb bufrd2 ; b = not yet, just return
mov bufrdptr,0 ; reset to start of buf (wrapping)
bufrd2: pop es
pop si
clc ; clear carry flag (have read a char)
ret ; chkport sets status
bufread endp
; Non-destructive read of serial port circular buffer. Requires external
; initialization of peek read pointer bufpkptr and count remaining bufpkcnt.
; Returns character in register al.
peekbuf proc near
cmp bufpkcnt,0 ; peek counter, empty buffer?
jne peekbu2 ; ne = no, so look in buffer
or status,stat_tmo ; force timeout status
push si
mov si,scpbuflen
cmp bufcnt,si ; is real buffer full?
pop si
jae peekbu1 ; ae = yes, have examined everything
call chkport ; get a char from port
and status,not stat_tmo ; clear timeout
call chktmo ; and check for timeout
cmp bufcnt,0 ; still nothing from port?
je peekbu1 ; e = no char, report fact
inc bufpkcnt ; got one, increase peek counter
jmp short peekbu2 ; go extract it
peekbu1:stc ; return nothing to see
ret
peekbu2:push si
push es
mov si,bufseg ; segment of port buffer
mov es,si
mov si,bufpkptr ; buffer peek pointer
mov al,es:[si] ; extract a char into al
inc bufpkptr ; move pointer to next byte
dec bufpkcnt ; say have extracted a char
mov si,scpbuflen
cmp bufpkptr,si ; beyond end?
jb peekbu3 ; b = not yet, just return
mov bufpkptr,0 ; reset to start of buf (wrapping)
peekbu3:pop es
pop si
clc ; clear carry flag (have read a char)
ret
peekbuf endp
bufwrite proc near
push si
push es
mov si,bufseg ; segment of buffer
mov es,si
mov si,bufwtptr
mov es:[si],al ; store char held in al
inc bufwtptr ; move pointer to next byte
mov si,scpbuflen ; length of buffer
cmp bufwtptr,si ; beyond end?
jb bufwt1 ; b = not yet
mov bufwtptr,0 ; reset to start of buf (wrapping)
bufwt1: inc bufcnt ; say have added a char to the buf
cmp bufcnt,si ; more than we can hold?
jbe bufwt3 ; be = not overflowing
push bufwtptr ; read ptr can't alias write ptr
pop bufrdptr ; move up read pointer
mov bufcnt,si ; limit count to max buffer length
bufwt3: pop es
pop si
ret
bufwrite endp
; Report buffer status for dumping buffer to a log file.
; Yield ax, cx, es, si as indicated below.
buflog proc near
mov ax,bufcnt ; number of unread chars
mov cx,scpbuflen ; length of buffer
mov si,bufseg ; segment of buffer
mov es,si
mov si,bufrdptr ; where to read next char
ret ; return these registers
buflog endp
; worker: check for timeout, return status=stat_tmo if timeout, else bit
; stat_tmo is cleared.
chktmo: and status,not stat_tmo
mov ah,gettim ; get the time of day
int dos
sub ch,timhms[0] ; hours difference, ch = (now-timeout)
je chktmo2 ; e = same, check mmss.s
jg chktmo1 ; g = past target hour
add ch,24 ; we are early, see by how much
chktmo1:cmp ch,12 ; hours difference, large or small?
jge chktmox ; ge = not that time yet
jl chktmo3 ; l = beyond that time
chktmo2:cmp cl,timhms[1] ; minutes, hours match
jb chktmox ; b = early
ja chktmo3 ; a = late
cmp dh,timhms[2] ; seconds, hhmm match
jb chktmox ; b = early
ja chktmo3 ; a = late
cmp dl,timhms[3] ; fractions, hhmmss match
jb chktmox ; b = early
chktmo3:or status,stat_tmo ; say timeout
stc
ret
chktmox:clc
ret
;
; worker: check keyboard for char. Return status = stat_cc if control-C typed,
; stat_cr if carriage return, or stat_ok if any other char typed. Else return
; with these status bits cleared.
chkkbd: and status,not (stat_ok+stat_cc+stat_cr) ; clear status bits
cmp flags.cxzflg,'C' ; Control-C interrupt seen?
je chkkbd0 ; e = yes
call isdev ; is stdin a device, not disk file?
jnc chkkbd2 ; nc = not device so do not read here
mov ah,dconio ; keyboard char present?
mov dl,0ffH
int dos
je chkkbd1 ; e = none
or status,stat_ok ; have a char, return it in al
cmp al,3 ; control c?
jne chkkbd1 ; ne = not control c
chkkbd0:or status,stat_cc ; say control c
chkkbd1:cmp al,cr ; carriage return? [js]
jne chkkbd2 ; ne = no
or status,stat_cr ; say carriage return [js]
chkkbd2:ret
;
; worker: check serial port for received char. Return status = stat_ok if
; char received, otherwise stat_ok cleared. Can echo char to screen. Will
; write char to local circular buffer.
chkport:and status,not stat_ok ; clear status bit
call prtchr ; char at port (in al)?
jnc chkpor1 ; nc = yes, analyze it
ret ; no, return
chkpor1:and al,parmsk ; strip parity, if any
cmp rxtable+256,0 ; is translation turned off?
je chkpor0 ; e = yes, no translation
push bx ; translate incoming character
mov bx,offset rxtable ; the translation table
xlatb
pop bx
chkpor0:test flags.capflg,logses ; capturing active?
jz chkpor3 ; z = no
test flags.remflg,d8bit ; keep 8 bits for displays?
jnz chkpo0a ; nz = yes, 8 bits if possible
cmp flags.debug,0 ; is debug mode active?
jne chkpo0a ; ne = yes, record 8 bits
and al,7fh ; remove high bit
chkpo0a:push ax ; save char
call cptchr ; give it captured character
pop ax ; restore character and keep going
chkpor3:test flags.remflg,d8bit ; keep 8 bits for displays?
jnz chkpo3a ; nz = yes, 8 bits if possible
and al,7fh ; remove high bit
chkpo3a:cmp script.inecho,0 ; input echoing off?
je chkpor4 ; e = yes
call scdisp ; display the char
chkpor4:call bufwrite ; put char in buffer
or status,stat_ok ; say have a char (still in al)
ret
;
; Squit is the script error exit pathway.
;
squit: cmp flags.cxzflg,'C' ; Control-C interrupt seen?
je squit5 ; e = yes
test status,stat_tmo ; timeout?
jz squit2 ; z = no, another kind of failure
cmp taklev,0 ; in a Take/macro?
jne squit1 ; ne = yes, skip timeout message
push dx
mov dx,offset tmomsg ; say timed out
mov ah,prstr
int dos ; display it
pop dx
squit1: cmp script.inactv,0 ; action to do upon timeout
je squit4 ; 0 = proceed, ne = non-zero = quit
squit5: call takclos ; close Take file or macro
squit2: call isdev ; stdin is a device (vs file)?
jc squit3 ; c = device, not a file
mov flags.extflg,1 ; set Kermit exit flag
squit3: cmp flags.cxzflg,'C' ; Control-C interrupt seen?
jne squit6 ; ne = no
or kstatus,ksuser ; say user intervention
squit6: stc
ret ; return failure
squit4: clc ; return success, ignore error
ret
code ends
end